<template>
  <el-container style="background: #eee">
    <el-header height="25%" class="os">
        <div class="osInfo">
          <img src="../assets/img.jpg" name="avatar" :title="loginTitle" @click="login">
          <div name="info">
            <p>ip：<span>{{ osInfo.ip }}</span></p>
            <p>总内存：<span>{{ (osInfo.totalmem / 1073741824).toFixed(2) }}G</span></p>
            <p>cpu：<span>{{ osInfo.cpu }}</span></p>
            <p>操作系统：<span>{{ osInfo.type }}</span></p>
          </div>
        </div>
        <div class="osStatus">
          <div name="progress">
            <el-progress type="dashboard" :percentage="osStatus.cpu.toFixed(2)" :color="colors" width="110"></el-progress>
            <div name="label">cpu</div>
          </div>
          <div name="progress">
            <el-progress type="dashboard" :percentage="memory" :color="colors" width="110"></el-progress>
            <div name="label">内存</div>
          </div>
        </div>
    </el-header>
    <el-main height="75%" class="serviceList">
      <ul class="title">
        <li style="width: calc(15% - 1px)" @click="setSort('name')">服务名<span v-if="sort === 'name'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(10% - 1px)" @click="setSort('status')">状态<span v-if="sort === 'status'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(15% - 1px)" @click="setSort('startTime')">启动时间<span v-if="sort === 'startTime'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(15% - 1px)" @click="setSort('stopTime')">停止时间<span v-if="sort === 'stopTime'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(10% - 1px)" @click="setSort('takeUpTime')">启动耗时<span v-if="sort === 'takeUpTime'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(15% - 1px)" @click="setSort('timeLength')">运行时长<span v-if="sort === 'timeLength'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(10% - 1px)" @click="setSort('memoryUsage')">内存占用<span v-if="sort === 'memoryUsage'">{{ order ? "▾" : "▴" }}</span></li>
        <li style="width: calc(10% - 1px)" title="无排序">操作</li>
      </ul>
      <div style="overflow: scroll; height: calc(100% - 40px)">
        <ul class="service" v-for="(service, index) in serviceList" :key="index">
          <li style="width: 15%">{{ service.name }}</li>
          <li style="width: 10%" v-html="status(service.status)"></li>
          <li style="width: 15%">{{ service.startTime }}</li>
          <li style="width: 15%">{{ service.stopTime }}</li>
          <li style="width: 10%">{{ service.takeUpTime }} s</li>
          <li style="width: 15%">{{ service.timeLength }}</li>
          <li style="width: 10%">{{ service.memoryUsage }}%</li>
          <li style="width: 10%">
            <img v-show="service.status === 'stop'" src="../assets/start.svg" @click="start(service.name)" title="运行">
            <img v-show="service.status !== 'stop'" src="../assets/stop.svg" @click="stop(service.name)" title="终止">
            <img v-show="service.status !== 'stop'" src="../assets/restart.svg" @click="restart(service.name)" title="重启">
          </li>
        </ul>
      </div>
    </el-main>
  </el-container>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import { socket } from "../init";
import moment from "moment";

@Component
export default class ServiceList extends Vue {
  public osInfo: OsInfo = {
    ip: "获取中...",
    totalmem: 1,
    cpu: "获取中...",
    type: "获取中...",
  };
  public services: Services = {};
  public osStatus: OsStatus = {
    freemem: 0,
    cpu: 0,
    timestamp: 0,
  };
  public sort = "name";
  public order = true;

  public colors = [
    {color: '#5cb87a', percentage: 30},
    {color: '#e6a23c', percentage: 60},
    {color: "#f56c6c", percentage: 90}
  ];

  public $router: any;

  public now = new Date().getTime();

  public socket = socket;

  public $confirm: any;

  public $message: any;

  private interval: NodeJS.Timeout;

  constructor(...args: any) {
    super(...args);

    socket.wsCallback({ type: "init" }, ({ osInfo, services }) => {
        Object.assign(this.osInfo, osInfo);
        for (const name in services) {
          Vue.set(this.services, name, services[name]);
        }
    });

    // 定时获取系统资源占用情况
    this.interval = setInterval(() => {
      socket.wsCallback({ type: "getOsStatus" }, (osStatus) => {
        Object.assign(this.osStatus, osStatus);
      });
      this.now = new Date().getTime();
    }, 1000);

    socket.on("fork", this.onFork);
    socket.on("exit", this.onExit);
    socket.on("running", this.onRunning);
    socket.on("memory", this.onMemory);
  }

  public onFork(message: any) {
    this.services[message.serviceName].status = "start";
    this.services[message.serviceName].startTime = message.startTime;
  }
  public onExit(message: any) {
    this.services[message.serviceName].status = "stop";
    this.services[message.serviceName].stopTime = message.stopTime;
  }
  public onRunning(message: any) {
    this.services[message.serviceName].status = "running";
    this.services[message.serviceName].runningTime = message.runningTime;
  }
  public onMemory(message: any) {
    this.services[message.serviceName].memoryUsage = message.memoryUsage;
  }

  public sortService(serviceList: any) {
    return serviceList.sort((service1: any, service2: any) => {
      if (service1[this.sort] === service2[this.sort]) {
        return 0;
      }
      if (this.order) {
        return service1[this.sort] > service2[this.sort] ? 1 : -1;
      } else {
        return service1[this.sort] < service2[this.sort] ? 1 : -1;
      }
    });
  }

  public timeLength(number: number) {
    let second = Math.round(number / 1000);
    if (second < 60) {
      return `00:00:${ second > 9 ? second : `0${ second }` }`;
    }
    let minute = Math.round(second / 60);
    second %= 60;
    if (minute < 60) {
      return `00:${ minute > 9 ? minute : `0${ minute }` }:${ second > 9 ? second : `0${ second }` }`;
    }
    let hour = Math.round(minute / 60);
    minute %= 60;
    return `${ hour > 9 ? hour : `0${ hour }` }:${ minute > 9 ? minute : `0${ minute }` }:${ second > 9 ? second : `0${ second }` }`;
  }

  public status(data: string) {
    switch (data) {
      case "running": return `<span style="color: green;">运行中</span>`;
      case "start": return `<span style="color: green;">启动中...</span>`;
      case "stop": return `<span style="color: #555;">未启动</span>`;
      case "restart": return `<span style="color: green;">重启中...</span>`;
      default: return `<span style="color: #555;">未知</span>`;
    }
  }

  public setSort(sort: string) {
    if (this.sort === sort) {
      this.order = !this.order;
    } else {
      this.order = true;
    }
    this.sort = sort;
  }

  public start(serviceName: string) {
      socket.send({
          serviceName,
          type: "start",
      });
  }
  public stop(serviceName: string) {
      socket.send({
          serviceName,
          type: "stop",
      });
  }

  public restart(serviceName: string) {
      this.services[serviceName].status = "restart";
      socket.send({
          serviceName,
          type: "restart",
      });
  }

  public beforeDestroy() {
    clearInterval(this.interval);
    socket.removeListener("fork", this.onFork);
    socket.removeListener("exit", this.onExit);
    socket.removeListener("running", this.onRunning);
    socket.removeListener("memory", this.onMemory);
  }

  public async login() {
    if (!socket.id) {
      this.$router.push('/login')
    } else {
      try {
        await this.$confirm("此操作会退出当前登录，确认操作吗？", "警告", {
          confirmButtonText: "确认",
          cancelButtonText: "取消",
          type: 'warning'
        });
        socket.send({ type: "logout" });
      } catch (error) {}
    }
  }

  get memory() {
    return (100 - (this.osStatus.freemem / this.osInfo.totalmem) * 100).toFixed(2)
  }

  get serviceList() {
      const list = [];
      for (const name in this.services) {
        const service = this.services[name];
        list.push({
          name,
          status: service.status,
          takeUpTime: service.status === "running" ? (service.runningTime - service.startTime) / 1000 : 0,
          timeLength: service.status === "running" ? this.timeLength(this.now - service.runningTime) :"00:00:00",
          memoryUsage: service.memoryUsage ? (service.memoryUsage.rss / this.osInfo.totalmem * 100).toFixed(2) : 0,
          stopTime: service.stopTime ? moment(new Date(service.stopTime)).format("YYYY-MM-DD hh:mm:ss") : "无",
          startTime: service.startTime ? moment(new Date(service.startTime)).format("YYYY-MM-DD hh:mm:ss") : "无",
        });
      }
      return this.sortService(list);
  }

  get loginTitle() {
    return this.socket.id ? "点击注销" : "点击登录";
  }
}

interface OsStatus {
    freemem: number;
    cpu: number;
    timestamp: number;
}

interface Service {
    name: string;
    status: string;
    stopTime: number;
    startTime: number;
    runningTime: number;
    memoryUsage: any;
}

interface Services {
    [serviceName: string]: Service;
}

interface OsInfo {
    ip: string;
    totalmem: number;
    cpu: string;
    type: string;
}

</script>

<style scoped>
.os {
  margin: 15px;
  background: #fff;
  padding: 0;
  border-radius: 2px;
}

.osInfo {
    background: #eee;
    height: calc(100% - 20px);
    width: calc(50% - 20px);
    margin: 10px;
    border-radius: 2px;
    font-size: 14px;
    float: left;
}

.osInfo p {
  margin: 0;
  line-height: 30px;
  padding-left: 30px;
}

.osInfo span {
  color: #616161;
}

.osInfo [name=info] {
  border-left: 1px #d1d1d1 solid;
  height: calc(100% - 40px);
  float: left;
  margin-top: 20px;
}

.osInfo [name=avatar] {
  height: calc(100% - 40px);
  margin: 20px 30px 20px 20px;
  float: left;
  cursor: pointer;
}

.osStatus {
  float: left;
  background: #eee;
  height: calc(100% - 20px);
  width: calc(50% - 10px);
  position: relative;
  margin: 10px 10px 10px 0;
}

.osStatus [name=progress] {
  float: left;
  width: 50%;
}

.osStatus [name=label] {
  position: relative;
  top: -20px;
  text-align: center;
}

.el-progress {
  margin: 20px 0 20px calc((100% - 110px) / 2);
}

.serviceList {
  margin: 0 15px 0 15px;
  background: #fff;
  height: 0%;
  padding: 0;
  overflow: hidden;
}

.title {
    height: 50px;
    background: #fff;
    padding: 0;
    margin: 0;
    border-bottom: 1px solid #dedede;
}

.title li {
    float: left;
    list-style: none;
    line-height: 50px;
    color: #000;
    font-size: 14px;
    text-align: center;
    cursor: pointer;
}

.title li:hover {
    font-weight: 600;
}

.title li>span {
    padding-left: 5px;
}

.service {
    height: 50px;
    padding: 0;
    margin: 0;
    border-bottom: 1px #f2f2f2 solid;
    transition: background-color .3s;
    cursor: pointer;
}

.service li {
    float: left;
    list-style: none;
    line-height: 50px;
    font-size: 14px;
    text-align: center;
}

.service:hover {
  background: #597ba70f;
  font-weight: 600;
  color: #409EFF;
}

.service li>img {
    width: 10%;
    cursor: pointer;
    padding-left: 15px;
}

::-webkit-scrollbar {
    width: 1px;
}

::-webkit-scrollbar-thumb {
    border-radius: 1px;
    background: #ccc;
}

::-webkit-scrollbar-track {
    border-radius: 1px;
}

</style>